package lesson5.example3.transformer;

import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.concurrent.ConcurrentHashMap;
import javassist.CtClass;
import lesson5.example5.ByteBuddyUtil;

public abstract class AbstractTransformer implements ClassFileTransformer {
	
   final static ConcurrentHashMap<String, ByteCache> MAP = new ConcurrentHashMap<>();
    
    protected void saveInitialSnapshot(String className, Class<?> classBeingRedefined, byte[] classfileBuffer) {
        if (!MAP.containsKey(className)) {
            MAP.putIfAbsent(className, new ByteCache(classBeingRedefined, classfileBuffer));
        }
    }   

	public static class ByteCache {
		Class<?> clazz;
		byte[] bytes;

		public ByteCache(Class<?> clazz, byte[] bytes) {
			this.clazz = clazz;
			this.bytes = bytes;
		}
	}
	
    protected String fullClassName;
    public AbstractTransformer(String fullClassName) {
    	this.fullClassName =fullClassName;
    }
    
    @Override
    public byte[] transform(
    		ClassLoader loader, 
    		String className, 
    		Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, 
            byte[] classfileBuffer ) {
        try {
            className = className.replace("/", ".");
            // 必须做这一层过滤， 实践发现即使调用ClassFileTransformer时指定了类，但还是会有其他类也被执行了transformer
            if (fullClassName!=null && !fullClassName.equals(className)) {
                return classfileBuffer;
            }
            
            CtClass cc = ByteBuddyUtil.classPool.get(className);
            saveInitialSnapshot(className, classBeingRedefined, classfileBuffer);
            
            // 如果一个CtClass对象通过writeFile()、toClass()、toBytecode()被转换成一个类文件，
            // 此CtClass对象会被冻结起来，不允许再修改，通过defrost方法可以解冻
            if (cc.isFrozen()) {
                cc.defrost();
            }
            
            return doTransform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer, cc);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    // 抽象方法，由具体的子类来实现
    public abstract byte[] doTransform(
    		ClassLoader loader, 
    		String className, 
    		Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, 
            byte[] classfileBuffer, 
            CtClass cc) throws Exception;
    
    
}    
